package cn.hg.solon.youcan.system.provider;

import static cn.hg.solon.youcan.system.entity.table.SysRoleDeptMappingTableDef.SYS_ROLE_DEPT_MAPPING;
import static cn.hg.solon.youcan.system.entity.table.SysRolePermissionMappingTableDef.SYS_ROLE_PERMISSION_MAPPING;
import static cn.hg.solon.youcan.system.entity.table.SysRoleTableDef.SYS_ROLE;
import static cn.hg.solon.youcan.system.entity.table.SysUserRoleMappingTableDef.SYS_USER_ROLE_MAPPING;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.solon.annotation.Db;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.text.StrValidator;
import org.dromara.hutool.core.util.ObjUtil;
import org.noear.solon.annotation.Component;

import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryColumn;
import com.mybatisflex.core.query.QueryOrderBy;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.solon.service.impl.ServiceImpl;

import cn.hg.solon.youcan.common.constant.AppConstants;
import cn.hg.solon.youcan.common.enums.BeanStatus;
import cn.hg.solon.youcan.common.exception.ServiceException;
import cn.hg.solon.youcan.system.entity.SysRole;
import cn.hg.solon.youcan.system.entity.SysRoleDeptMapping;
import cn.hg.solon.youcan.system.entity.SysRolePermissionMapping;
import cn.hg.solon.youcan.system.entity.SysUser;
import cn.hg.solon.youcan.system.mapper.SysRoleDeptMappingMapper;
import cn.hg.solon.youcan.system.mapper.SysRoleMapper;
import cn.hg.solon.youcan.system.mapper.SysRolePermissionMappingMapper;
import cn.hg.solon.youcan.system.service.SysRoleService;

/**
 * @author 胡高
 */
@Component
public class SysRoleProvider extends ServiceImpl<SysRoleMapper, SysRole> implements SysRoleService {

    @Db
    SysRoleDeptMappingMapper roleDeptMappingMapper;

    @Db
    SysRolePermissionMappingMapper rolePermissionMappingMapper;

    @Override
    public void assignDataScope(SysRole role, String dataScope, List<Integer> deptIdArray) {
        this.updateDataScope(role, deptIdArray);

        role.setDataScope(dataScope);

        this.update(role);
    }

    @Override
    public void assignPermission(SysRole role, List<Integer> permissionIdArray) {
        this.updateRolePermissions(role, permissionIdArray);

        this.update(role);
    }

    private QueryWrapper buildQuery(Map<String, Object> map) {
        String word = (String)map.get("word");
        String status = (String)map.get("status");
        String sortField = (String)map.get("sortField");
        String sortType = (String)map.get("sortType");
        QueryWrapper query = QueryWrapper.create()
            .where(SYS_ROLE.STATUS.eq(status).when(StrValidator.isNotBlank(status))
                .and(SYS_ROLE.NAME.like(word).when(StrValidator.isNotBlank(word))
                    .or(SYS_ROLE.CODE.like(word).when(StrValidator.isNotBlank(word)))
                )
            ).orderBy(new QueryOrderBy(new QueryColumn(StrUtil.toUnderlineCase(sortField)), sortType));

        return query;
    }

    @Override
    public boolean checkUnique(SysRole bean) {
        // 查找已存在记录
        QueryWrapper query = QueryWrapper.create()
            .where(SYS_ROLE.CODE.eq(bean.getCode()).and(SYS_ROLE.ID.ne(bean.getId())));

        return ObjUtil.isNull(this.getOne(query));
    }


    /* (non-Javadoc)
     * @see cn.hg.solon.youcan.system.service.SysRoleService#getByTypeAndCode(java.lang.String, java.lang.String)
     */
    @Override
    public SysRole getByCode(String code) {
        QueryWrapper query = QueryWrapper.create().where(SYS_ROLE.CODE.eq(code));
        return this.getOne(query);
    }

    @Override
    public List<SysRole> listByMap(Map<String, Object> map) {
        return this.list(this.buildQuery(map));
    }

    @Override
    public List<SysRole> listByStatus(String status) {
        return this.list(this.buildQuery(MapUtil.of("status", status)));
    }

    /*
     * (non-Javadoc)
     * @see cn.hg.solon.youcan.system.service.SysRoleService#selectListByUser(cn.hg.solon.youcan.system.entity.SysUser)
     */
    @Override
    public List<SysRole> listByUser(SysUser user) {
        /*
            SELECT r.*
            FROM sys_role AS r
                LEFT JOIN sys_user_role_mapping AS ur ON ur.role_id = r.id
            WHERE r.del = 0 AND r.`status` = 'ON' AND ur.user_id = #para(userId)
            ORDER BY r.sort
         */
        QueryWrapper query = QueryWrapper.create()
            .leftJoin(SYS_USER_ROLE_MAPPING).on(SYS_USER_ROLE_MAPPING.ROLE_ID.eq(SYS_ROLE.ID))
            .where(SYS_ROLE.STATUS.eq(BeanStatus.ON.name())
                .and(SYS_USER_ROLE_MAPPING.USER_ID.eq(user.getId()))
            );

        return this.list(query);
    }

    @Override
    public Page<SysRole> pageByMap(Page<SysRole> page, Map<String, Object> map) {
        return this.page(page, this.buildQuery(map));
    }

    @Override
    public boolean save(SysRole bean) {
        if (!this.checkUnique(bean)) {
            throw new ServiceException(AppConstants.RETURN_CODE_VALUE_FAILED, "权限代码已经存在，请更换其它值！");
        }

        return this.save(bean);
    }

    @Override
    public boolean update(SysRole bean) {
        if (!this.checkUnique(bean)) {
            throw new ServiceException(AppConstants.RETURN_CODE_VALUE_FAILED, "权限代码已经存在，请更换其它值！");
        }

        return this.updateById(bean);
    }

    private void updateDataScope(SysRole role, List<Integer> permissionIds) {
        /*
         * 删除所有权限
         */
        QueryWrapper query = QueryWrapper.create().where(SYS_ROLE_DEPT_MAPPING.ROLE_ID.eq(role.getId()));
        this.roleDeptMappingMapper.deleteByQuery(query);

        /*
         * 重新建立角色权限
         */
        List<SysRoleDeptMapping> beanList = new ArrayList<>();
        for (int id : permissionIds) {
            SysRoleDeptMapping bean = new SysRoleDeptMapping();
            bean.setRoleId(role.getId());
            bean.setDeptId(id);

            beanList.add(bean);
        }

        if (CollUtil.isNotEmpty(beanList)) {
            this.roleDeptMappingMapper.insertBatch(beanList);
        }
    }

    private void updateRolePermissions(SysRole role, List<Integer> permissionIds) {
        /*
         * 删除所有权限
         */
        QueryWrapper query = QueryWrapper.create().where(SYS_ROLE_PERMISSION_MAPPING.ROLE_ID.eq(role.getId()));
        this.rolePermissionMappingMapper.deleteByQuery(query);

        /*
         * 重新建立角色权限
         */
        List<SysRolePermissionMapping> beanList = new ArrayList<>();
        for (int id : permissionIds) {
            SysRolePermissionMapping bean = new SysRolePermissionMapping();
            bean.setRoleId(role.getId());
            bean.setPermissionId(id);

            beanList.add(bean);
        }
        if (CollUtil.isNotEmpty(beanList)) {
            this.rolePermissionMappingMapper.insertBatch(beanList);
        }
    }

}
